package dcutils.sock;

// Import Java JDK Classes
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

/**
 * A connection
 * @author dca
 */
public class Connection implements Runnable {
   private int id;
   private Socket socket;
   private List<String> breakStrings;
   private List<AsyncInput> asyncInputs;

   public Connection(Socket socket, List<String> breakStrings) {
      this(-1, socket, breakStrings);
   } // END connection

   public Connection(int id, Socket socket, List<String> breakStrings) {
      this.id = id;
      this.socket = socket;
      this.breakStrings = breakStrings;
      this.asyncInputs = new ArrayList<AsyncInput>();

      new Thread(this, Connection.class.getSimpleName()).start();
   } // END connection

   public boolean isClosed() {
      return socket.isClosed();
   } // END isClosed

   public void registerAsyncInput(AsyncInput ai) {
      this.asyncInputs.add(ai);
   } // END registerAsyncInput

   @Override
   public void run() {
      String line = "";
      try(BufferedReader socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {
         while((line = socketIn.readLine()) != null) {
            System.out.println(line); // Print socket input (client or server)

            if(line.matches("^.*YOUR_ID=\\d\\d*$")) id = Integer.parseInt(line.replaceAll("^.*YOUR_ID=", "")); // Assign connection ID

            if(this.breakStrings.contains(line.replaceAll("(?i)^" + Connection.class.getSimpleName() + "\\(\\d\\d*\\): ", ""))) break;
         } // END loop
      } catch(Exception exc) {
         System.out.printf("Warning: %s: Could not read from socket.  Message was: %s%n", exc.getClass().getSimpleName(), exc.getMessage());
         exc.printStackTrace();
      } finally {
         closeSocket();
         deactivateAsyncInputs();
      } // END try/catch
   } // END run

   public void send(String text) throws IOException {
      new PrintStream(socket.getOutputStream(), true).printf("Connection(%d): %s%n", id, text);
   } // END send

   public void closeSocket() {
      try {
         System.out.println("Closing socket.");
         socket.close();
      } catch(Exception exc) {
         System.out.printf("Warning: %s: Could not close socket.  Message was: %s%n", exc.getClass().getSimpleName(), exc.getMessage());
         exc.printStackTrace();
      } // END try/catch
   } // END closeSocket

   private void deactivateAsyncInputs() {
      if(null != this.asyncInputs) {
         System.out.println("Deactivating AsyncInput instances.");
         for(AsyncInput ai : this.asyncInputs) {
            System.out.println("Deactivating AsyncInput instance.");
            ai.deactivate();
         } // END loop
      } // END if
   } // END deactivateAsyncInputs

   public int getId() {
      return this.id;
   } // END getId
} // END class Connection
